﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Cloak.NUnit;
using Cloak.Reflection;
using NUnit.Framework;

namespace Ruleweaver.Rules.CheckMethods
{
	public class GetRule : Behavior
	{
		private Type _targetType;
		private int _argument;
		private MethodInfo _method;
		private TestCheckMethod _checkMethod;
		private CheckRule _rule;

		protected override void Given()
		{
			_targetType = typeof(int);
			_argument = 1;

			_method = Reflect.Func<ICheckable<int>, int, Check<int>>(Checkable.IsEqualTo);

			_checkMethod = new TestCheckMethod(_method);
		}

		protected override void When()
		{
			_rule = _checkMethod.GetRule(_targetType);
		}

		[Then]
		public void RuleAppliesCheck()
		{
			Assert.AreEqual(_method, _rule.Method);
		}

		[Then]
		public void RuleHasCheckArguments()
		{
			Assert.IsTrue(_rule.CheckArguments.SequenceEqual(new object[] { _argument }));
		}

		[Then]
		public void TargetTypeGivenToSupportsTargetType()
		{
			Assert.AreEqual(_targetType, _checkMethod.TargetTypeForSupportsTargetType);
		}

		[Then]
		public void TargetTypeGivenToGetMethod()
		{
			Assert.AreEqual(_targetType, _checkMethod.TargetTypeForGetMethod);
		}

		[Then]
		public void CheckTypeGivenToGetMethod()
		{
			var checkType = typeof(ICheckable<>).MakeGenericType(_targetType);

			Assert.AreEqual(checkType, _checkMethod.CheckTypeForGetMethod);
		}

		[Then]
		public void TargetTypeGivenToGetCheckArguments()
		{
			Assert.AreEqual(_targetType, _checkMethod.TargetTypeForGetCheckArguments);
		}

		private sealed class TestCheckMethod : CheckMethod
		{
			private readonly MethodInfo _method;

			internal TestCheckMethod(MethodInfo method)
			{
				_method = method;
			}

			internal Type TargetTypeForSupportsTargetType { get; private set; }

			internal Type TargetTypeForGetMethod { get; private set; }

			internal Type CheckTypeForGetMethod { get; private set; }

			internal Type TargetTypeForGetCheckArguments { get; private set; }

			protected override bool SupportsTargetType(Type targetType)
			{
				TargetTypeForSupportsTargetType = targetType;

				return true;
			}

			protected override MethodInfo GetMethod(Type targetType, Type checkType)
			{
				TargetTypeForGetMethod = targetType;
				CheckTypeForGetMethod = checkType;

				return _method;
			}

			protected override IEnumerable<object> GetCheckArguments(Type targetType)
			{
				TargetTypeForGetCheckArguments = targetType;

				yield return 1;
			}
		}
	}
}